#ifndef LINKED_LIST_H
#define LINKED_LIST_H

#include <iostream>

class Node
{
public:
	Node(int data, Node *next=0) : data(data), next(next) {}
	int data;
	Node *next;
};

class ListIteratorException
{
public:
	ListIteratorException(const std::string &message) : message(message) {}
	std::string message;
};

class ListIterator
{
	friend std::ostream &operator <<(std::ostream &os, const ListIterator &array);
public:
	ListIterator(Node *current) :
      current(current)
   {
   }

	int &operator *()
   {
      if (current == NULL)
      {
         throw ListIteratorException("Cannot dereference iterator. List is empty or iterator points beyond the end");
      }
      return current->data;
   }

	ListIterator operator ++()
   {
      if (current == NULL)
      {
         throw ListIteratorException("Cannot increment iterator. List is empty or iterator points beyond the end");
      }
      current = current->next;
      return *this;
   }
   
	bool operator ==(const ListIterator &other) {return current == other.current;} 
	bool operator !=(const ListIterator &other) {return !(*this == other);}
private:
	Node *current;
};

class LinkedList
{
	friend std::ostream &operator <<(std::ostream &os, const LinkedList &linkedList);
public:
	LinkedList();
   ~LinkedList();
	void insert(int value);
	ListIterator begin() { return ListIterator(head);}
	ListIterator end() {return ListIterator(0);}
private:
	Node *head;
};

#endif
